/*
 * commons is a based project implemented
 * Copyright (C) 2024 Jasmine
 */
package com.commons.core.validator;

import static java.lang.annotation.ElementType.*;
import static java.lang.annotation.RetentionPolicy.RUNTIME;

import java.lang.annotation.*;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.Objects;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import jakarta.validation.Constraint;
import jakarta.validation.ConstraintValidator;
import jakarta.validation.ConstraintValidatorContext;
import jakarta.validation.Payload;

/**
 * 使用： ① @EnumValidator(value = ProjectEnum.StatusEnum.class, message = "项目状态只允许为: 0-未开始 1-进行中 2-已完结")
 * ② @EnumValidator(enumValues = {"F","M"} ,message = "性别只允许为F或M")
 * <p>
 * 注意：如果使用第一种方法的话，默认枚举类中提供getCode方法，否则就要给method赋值
 *
 * @author Jasmine
 */
@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.FIELD, ElementType.METHOD})
@Constraint(validatedBy = EnumValidator.EnumValidatorHandle.class)
public @interface EnumValidator {

    Class<?> value() default Object.class;

    String method() default "getCode";

    String message() default "入参值不在正确枚举中";

    /**
     * 自定义枚举值
     */
    String[] enumValues() default {};

    Class<?>[] groups() default {};

    Class<? extends Payload>[] payload() default {};

    @Target({METHOD, FIELD, ANNOTATION_TYPE, CONSTRUCTOR, PARAMETER, TYPE_USE})
    @Retention(RUNTIME)
    @Documented
    @interface List {
        EnumValidator[] value();
    }

    class EnumValidatorHandle implements ConstraintValidator<EnumValidator, Object> {

        Logger log = LoggerFactory.getLogger(EnumValidatorHandle.class);

        private java.util.List<Object> values = new ArrayList<>();

        @Override
        public void initialize(EnumValidator enumValidator) {
            String[] enumValues = enumValidator.enumValues();
            if (Objects.nonNull(enumValues) && enumValues.length > 0) {
                for (String value : enumValues) {
                    values.add(value);
                }
            }

            Class<?> clz = enumValidator.value();
            boolean assignableFrom = clz.isAssignableFrom(Object.class);
            if (assignableFrom) {
                return;
            }
            Object[] objects = clz.getEnumConstants();
            try {
                Method method = clz.getMethod(enumValidator.method());
                if (Objects.isNull(method)) {
                    throw new RuntimeException(String.format("枚举对象%s缺少名为%s的方法", clz.getName(), enumValidator.method()));
                }
                Object value;
                for (Object obj : objects) {
                    value = method.invoke(obj);
                    values.add(value);
                }
            } catch (Exception e) {
                log.error("处理枚举校验异常:{}", e);
            }
        }

        @Override
        public boolean isValid(Object value, ConstraintValidatorContext constraintValidatorContext) {
            boolean flag = Objects.isNull(value) || values.contains(value);
            return flag;
        }
    }

}
